package com.itchen.school.common.utils;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.itchen.school.common.exception.SysException;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import org.apache.poi.util.IOUtils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.Objects;

public class ExcelExportUtils {

    private static final Logger LOGGER = LoggerFactory.getLogger(ExcelExportUtils.class);

    public static <T> List<T> read(String filePath, final Class<?> clazz) {
        File f = new File(filePath);
        try (FileInputStream fis = new FileInputStream(f)) {
            return read(fis, clazz);
        } catch (FileNotFoundException e) {
            LOGGER.error("文件{}不存在", filePath, e);
        } catch (IOException e) {
            LOGGER.error("文件读取出错", e);
        }
        return null;
    }

    public static <T> List<T> read(InputStream inputStream, final Class<?> clazz) {
        if (inputStream == null) {
            throw new SysException("解析出错了，文件流是null");
        }
        // 有个很重要的点 DataListener 不能被spring管理，要每次读取excel都要new,然后里面用到spring可以构造方法传进去
        DataListener<T> listener = new DataListener<>();
        // 这里 需要指定读用哪个class去读，然后读取第一个sheet 文件流会自动关闭
        EasyExcel.read(inputStream, clazz, listener).sheet().doRead();
        return listener.getRows();
    }

    public static File createFileFromMultipartFile(MultipartFile file) {
        String dirPath = "." + File.separator + "uploads" + File.separator + "temporary";
        File dir = new File(dirPath);
        if (!dir.exists() || !dir.isDirectory()) {
            dir.mkdirs();
        }

        File fileTemp = new File(dirPath + File.separator + IdWorker.get32UUID() + "." + SysFileUtils.getExtensionName(Objects.requireNonNull(file.getOriginalFilename())));
        if (fileTemp.exists()) {
            fileTemp.delete();
        }

        try {
            fileTemp.createNewFile();
            SysFileUtils.saveFileToDisk(file.getInputStream(), fileTemp.getCanonicalPath());
            return fileTemp;
        } catch (IOException var6) {
            throw new SysException("传输文件失败!!", var6);
        }
    }

    private static File createFileFromMultipartFile(InputStream file) {
        String dirPath = "."+File.separator + "uploads" + File.separator+"createExcel";
        File dir = new File(dirPath);
        if (!(dir.exists()&&dir.isDirectory())) {
            dir.mkdirs();
        }

        File fileTemp  = new File(dirPath+File.separator + IdWorker.get32UUID() +".xls");
        if(fileTemp.exists()) {
            fileTemp.delete();
        }
        try {
            fileTemp.createNewFile();
            SysFileUtils.saveFileToDisk(file, fileTemp.getCanonicalPath());
            return fileTemp;
        } catch (IOException e) {
            throw new SysException("传输文件失败!!",e);
        }
    }

    /**
     * 将传入的文件导入成对象
     */
    public static <T> List<T> importExcel(File file, final Class<?> clazz) {
        try (FileInputStream fis = new FileInputStream(file)) {
            return read(fis, clazz);
        } catch (FileNotFoundException e) {
            LOGGER.error("文件不存在", e);
        } catch (IOException e) {
            LOGGER.error("文件读取出错", e);
        }
        return null;
    }

    /**
     * 将指定位置指定名称的Excel文件 导出到web浏览器
     */
    public static void exportFileWeb(HttpServletResponse response, String path, String fileName) throws UnsupportedEncodingException {
        File file = new File(path);
        if (!file.exists()) {
            LOGGER.error("文件不存在！");
        }
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/vnd.ms-excel");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8);
        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ExcelTypeEnum.XLS.getValue());
        try (
                FileInputStream in = new FileInputStream(file);
                ServletOutputStream out = response.getOutputStream()
        ) {
            IOUtils.copy(in, out);
            LOGGER.error("导出成功！");
        } catch (Exception e) {
            LOGGER.error("导出文件异常：", e);
        }
        LOGGER.error("导出失败！");
    }

    /**
     * 将传入的列表数据导出成excel文件并下载到web浏览器上
     */
    public static void exportExcel(HttpServletResponse response, List<?> importlist, String[] titleNames, String fileName) {
        // 生成表格
        HSSFWorkbook workbook = createExcel(titleNames, importlist);
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/octet-stream");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8);
        response.setHeader("Content-Disposition", "attachment;fileName=" + fileName + ExcelTypeEnum.XLS.getValue());
        try {
            OutputStream outputStream = response.getOutputStream();
            // EasyExcel写操作
            workbook.write(outputStream);
            // 关闭数据流
            outputStream.flush();
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据表格的标题和表格数据，生成一个excel表格到指定的目录下 /uploads/...  并返回文件名
     */
    public static String listConverExcel(String[] titleNames, List<String[]> list) throws UnsupportedEncodingException {
        // 生成表格
        HSSFWorkbook workbook = createExcel(titleNames, list);
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        InputStream is = null;
        try {
            workbook.write(bos);
            byte[] barray = bos.toByteArray();
            is = new ByteArrayInputStream(barray);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 生成excel文件到指定的目录下
        File fileTemp = createFileFromMultipartFile(is);
        // 返回文件名
        return  fileTemp.getName();
    }

    /**
     * 根据表格的标题和表格数据，生成一个excel表格
     */
    private static HSSFWorkbook createExcel(String[] titleNames, List<?> importlist) {
        // 第一步，创建一个webbook，对应一个Excel文件   声明一个工作薄
        HSSFWorkbook workbook = new HSSFWorkbook();
        // 第二步，在webbook中添加一个sheet,对应Excel文件中的sheet   生成一个表格
        HSSFSheet sheet = workbook.createSheet();
        // 设置表格默认列宽度为15个字节
        sheet.setDefaultColumnWidth((short) 18);
        // 设置标题字体样式
        HSSFFont titleFont = workbook.createFont();
        HSSFCellStyle titleStyle = workbook.createCellStyle();
        titleFont.setBold(true);  // 加粗
        titleFont.setFontHeightInPoints((short) 12);  //设置字体大小
        //titleStyle.setAlignment(HorizontalAlignment.CENTER);  // 居中
        titleStyle.setFont(titleFont);

        // 循环字段名数组，创建标题行
        Row row = sheet.createRow(0);
        for (int i = 0; i < titleNames.length; i++) {
            // 创建列
            Cell cell = row.createCell(i);
            cell.setCellStyle(titleStyle);
            cell.setCellValue(titleNames[i]);
        }
        // 循环表格内容，创建普通行
        for (int j = 0; j < importlist.size(); j++) {
            //因为第一行已经用于创建标题行，故从第二行开始创建
            row = sheet.createRow(j + 1);
            //如果是第一行就让其为标题行
            String[] rowDate = (String[]) importlist.get(j);
            for (int k = 0; k < rowDate.length; k++) {
                //创建列
                Cell cell = row.createCell(k);
                cell.setCellValue(rowDate[k]);
            }
        }

        return workbook;
    }

}
